/**
 * \file main.cpp
 * \author T. M. Jandreau
 * \date December 22, 2012
 */

#include "../UnitTestHelper.h"

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <cppunit/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/XmlOutputter.h>

namespace TEST {

    ///\brief This class tests the unit test helper

    /**
     * \class TestUnitTestHelper
     * 
     * This class is responsible for setting up the unit test helper functions
     * and testing those. For the unit tests to be built on top of tools that have
     * been untested is dangerouse. This class publically inherits CPPUNIT_NS::TestCase
     * for virtual setUp() and takeDown() functions, which are essentially 
     * constructors and destructors
     */
    class TestUnitTestHelper : public CPPUNIT_NS::TestCase {
        CPPUNIT_TEST_SUITE(TestUnitTestHelper);
        CPPUNIT_TEST(validateFilePresence);
        CPPUNIT_TEST(getNumberOfFiles);
        CPPUNIT_TEST(purgeFile);
        CPPUNIT_TEST_SUITE_END();
    public:

        ///\brief Virtual "constructor" for TestUnitTestHelper

        /**
         * This is a virtually inherited function which serves as a sort of
         * constructor class for TestUnitTestHelper. This function creates
         * a file for the remaining unit tests to delete.
         */
        void setUp() {
            try {
                // want to define home directory
                home = getenv("HOME");
                workingDirectory = home + "/jarss/test/unitTestHelper/data";
                workingFile = workingDirectory + "/deleteThisFile.delete";
                persistentFile = workingDirectory + "/doNotDelete.test";
                // want to create a file to delete
                std::ofstream outfile;
                outfile.open(workingFile.c_str());
                outfile << "I am full of garbage";
                outfile.close();
            } catch (const std::ofstream::failure e) {
                // caught ostream error
                std::cerr << "Unable to open outstream " << e.what() << std::endl;
            } catch (...) {
                // caught unexpected error
                std::cerr << "Caught unhandled exception" << std::endl;
            }
        }

        ///\brief Virtual "destructor" for TestUnitTestHelper

                /**
         * This is a virtually inherited function which serves as a sort of
         * destructor class for TestUnitTestHelper. This function deletes the created
         * file should the unit testing fail.
         */
        void tearDown() {
            // if the file wasn't removed by the unit test, manually remove it
            if (TEST::validateFile(workingFile)) {
                remove(workingFile.c_str());
            }
        }

        ///\brief Standard home path based on the current user
        std::string home;

        ///\brief Working directory for the current thing
        std::string workingDirectory;

        ///\brief This is the working file for this unit test
        std::string workingFile;

        ///\brief This is the persistant file for the unit test
        std::string persistentFile;

    protected:


        ///\brief Function validates file presence

        /**
         * This function validates the file presence before the other unit tests.
         * This function ensures that our persistent file is always there.
         */
        void validateFilePresence() {
            bool validFile = TEST::validateFile(persistentFile);
            CPPUNIT_ASSERT(validFile);
        }

        ///\brief Returns the number of persistant files present in directory

        /**
         * This function ensures the correct number of persistent files are
         * present in the data directory.
         */
        void getNumberOfFiles() {
            int numFiles = TEST::getNumberOfFiles(workingDirectory, "test");
            CPPUNIT_ASSERT_EQUAL(1, numFiles);
        }

        ///\brief Purges the volatile file in the data directory

        /**
         * This function first ensures that the volatile file is present. It then
         * purges the file and ensures that a file is no longer there.
         */
        void purgeFile() {
            // this function will purge the file and insure it is no longer present
            bool validFile = TEST::validateFile(workingFile);
            CPPUNIT_ASSERT(validFile);

            // shows that the file is present at the start of the test
            TEST::purgeExistingFiles(workingDirectory, "delete");
            validFile = TEST::validateFile(workingFile);
            // now this shouldn't be present, 
            CPPUNIT_ASSERT_ASSERTION_FAIL(CPPUNIT_ASSERT(validFile));
            // assert that the assertion failed
        }
    };

} // namespace TEST


/***********************************************************/
// main starts below

CPPUNIT_TEST_SUITE_REGISTRATION(TEST::TestUnitTestHelper);

int main() {

    // creates the event manager and controller
    CPPUNIT_NS::TestResult controller;

    // adds a listener
    CPPUNIT_NS::TestResultCollector result;
    controller.addListener(&result);

    // adds something that prints progress
    CPPUNIT_NS::BriefTestProgressListener progress;
    controller.addListener(&progress);

    // add the top suite to the test runner
    CPPUNIT_NS::TestRunner runner;
    runner.addTest(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest());
    runner.run(controller);

    CPPUNIT_NS::CompilerOutputter compilerOutputter(&result, std::cout);
    compilerOutputter.write();

    ///home/tjandreau/DEV/TestResults
    std::string testResults = "../results/TestUnitTestHelper.xml";
    std::cout << " Writing output - " << testResults << std::endl;
    std::ofstream xmlFileOut(testResults.c_str());
    CPPUNIT_NS::XmlOutputter xmlOut(&result, xmlFileOut);
    xmlOut.write();

    return result.wasSuccessful() ? 0 : 1;
}

